package com.leaf.spring.y202002.day11.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class Server implements Runnable {

	// 多路复用器（管理所有的通道）
	private Selector selector;

	// 建立缓冲区
	private ByteBuffer readBuf = ByteBuffer.allocate(1024);
	private ByteBuffer writeBuf = ByteBuffer.allocate(1024);

	public Server(int port) {

		try {
			// 打开多路复用器
			selector = Selector.open();
			// 打开服务器通道
			ServerSocketChannel ssc = ServerSocketChannel.open();

			// 设置服务器通道为非阻塞状态
			ssc.configureBlocking(false);

			// 绑定地址
			ssc.bind(new InetSocketAddress(port));
			// 把服务器通道注册到多路复用器上，并且监听阻塞事件
			ssc.register(selector, SelectionKey.OP_ACCEPT);

			System.out.println("server start ,port : " + port);

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	@Override
	public void run() {

		while (true) {
			try {
				// 1 让多路复用器开始监听
				selector.select();
				// 2 返回多路复用器已经选择的结果集
				Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
				// 3 进行遍历
				while (iterator.hasNext()) {
					// 4 获取一个选择元素
					SelectionKey key = iterator.next();
					// 5 直接从容器中移除就可以了
					iterator.remove();
					// 6 如果是有效的
					if (key.isValid()) {
						// 7 如果为阻塞状态
						if (key.isAcceptable()) {
							accept(key);
						}
						// 8 如果为可读状态
						if (key.isReadable()) {
							read(key);
						}
						// 9 写数据
						if (key.isWritable()) {
							write(key);
						}
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}

	private void write(SelectionKey key) {

	}

	private void read(SelectionKey key) {

		try {
			// 1 清空缓存区中旧的数据
			readBuf.clear();

			// 2 获取之前注册的socket通道对象
			SocketChannel sc = (SocketChannel) key.channel();

			// 3 读取数据
			int count = sc.read(this.readBuf);

			// 4 如果没有数据
			if (count == -1) {
				key.channel().close();
				key.cancel();
				return;
			}

			// 5 有数据则进行读取，读取之前需要进行复位（把position和limit进行复位）
			readBuf.flip();

			// 6 根据缓冲区的数据长度创建相应大小的byte数组，接收缓冲区的数据
			byte[] bytes = new byte[readBuf.remaining()];

			// 7接收缓冲区的数据
			readBuf.get(bytes);

			// 8 打印结果
			String body = new String(bytes).trim();

			System.out.println("server :" + body);

			// 9可以写回给客户端数据

		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	private void accept(SelectionKey key) {

		try {
			// 1 获取服务通道
			ServerSocketChannel channel = (ServerSocketChannel) key.channel();
			// 2 执行阻塞方法
			SocketChannel sc = channel.accept();

			// 3设置阻塞模式
			sc.configureBlocking(false);

			// 4注册到多路复用器上，并设置读取标识
			sc.register(selector, SelectionKey.OP_READ);

		} catch (IOException e) {
			e.printStackTrace();
		}

	}
	
	public static void main(String[] args) {
		new Thread(new Server(5678)).start();
	}

}
